package Tools;

import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.geom.Vector2f;

import Game.GameHelper;
import GameMath.GPoint;

/** Metrics tool class
 * @author Aikidos
 */
public class Metrics {

	/** Shows the position of a sprite
	 * @param sprite - Sprite
	 */
	static public void PlacementSprite(Image sprite) {
		Input input = GameHelper.getGame().getInput();
		
		// Get mouse position
		GPoint mousePos = new GPoint(input.getMouseX(), 
				input.getMouseY());
		
		// Show mouse position
		GameHelper.getGame().setTitle(mousePos.toString());
		
		// Draw sprite
		sprite.draw(mousePos.x, mousePos.y);
	}
	
	/** Calculate distance between two vectors
	 * @param v1 - Vector1
	 * @param v2 - Vector2
	 * @return Distance
	 */
	static public float getDistance(Vector2f v1, Vector2f v2) {
		return v1.distance(v2);
	}
	
	/** Calculate distance between two points
	 * @param p1 - Point1
	 * @param p2 - Point2
	 * @return Distance
	 */
	static public float getDistance(GPoint p1, GPoint p2) {
		return p1.distance(p2);
	}

	/** Smooth movement (decrease speed)
	 * @param currentPos - Current position
	 * @param finishPos - Finish position
	 * @param delta - Time delta
	 * @param speed - Speed
	 * @param startSmoothDistance - Start smooth distance
	 * @return New position
	 */
	static public Vector2f smoothMovement(Vector2f currentPos, Vector2f finishPos, int delta, float speed, float startSmoothDistance)
    {
        if (currentPos != finishPos)
        {
            // Calculate distances
            float currDist = getDistance(currentPos, finishPos);

            // Create move vector
            Vector2f moveVector = getMoveVector(currentPos, finishPos);

            // Calculate distance
            float curSpeed = speed;

            if (currDist < startSmoothDistance)
                curSpeed = currDist / (startSmoothDistance / speed);

            // Return new position
            Vector2f newPos = currentPos;
            newPos.x += (moveVector.x * (curSpeed * (delta / 16)));
            newPos.y += (moveVector.y * (curSpeed * (delta / 16)));

            if (getDistance(newPos, finishPos) > currDist)
                newPos = finishPos;

            if (getDistance(newPos, finishPos) < 0.5f)
                newPos = finishPos;

            return newPos;
        }

        return finishPos;
    }

	/** Smooth movement (increase speed)
	 * @param startPos - Start position
	 * @param currentPos - Current position
	 * @param finishPos - Finish position
	 * @param delta - Time delta
	 * @param speed - Speed
	 * @param smoothDistance - Smooth distance
	 * @return New position
	 */
    static public Vector2f smoothMovement(Vector2f startPos, Vector2f currentPos, Vector2f finishPos, int delta, float speed, float smoothDistance)
    {
        if (currentPos != finishPos)
        {
            if (getDistance(currentPos, finishPos) < (speed * (delta / 16)))
                return finishPos;

            // Create move vector
            Vector2f moveVector = new Vector2f(0, 0);

            moveVector = (startPos == finishPos)
                             ? new Vector2f(1, 1)
                             : getMoveVector(startPos, finishPos);

            // Calculate distance
            float curSpeed = speed;

            if (startPos == currentPos)
                curSpeed = speed / 100f;
            else
            {
                float curDist = getDistance(startPos, currentPos);
                if (curDist < smoothDistance)
                    curSpeed = curDist / (smoothDistance / speed);
            }

            // Return new position
            Vector2f newPos = currentPos;
            newPos.x += (moveVector.x * (curSpeed * (delta / 16)));
            newPos.y += (moveVector.y * (curSpeed * (delta / 16)));

            if (getDistance(newPos, finishPos) < 0.5f)
                newPos = finishPos;

            return newPos;
        }

        return finishPos;
    }

    /** Smooth increment
     * @param start - Start value
     * @param finish - Finish value
     * @param delta - Time delta
     * @param speed - Speed
     * @param smoothDistance - Smooth distance
     * @param rounding - Rounding
     * @return New value
     */
    static public float smoothIncrement(float start, float finish, int delta, float speed, float smoothDistance, float rounding)
    {
        if (start != finish)
        {
            float result = 0;

            // Get current distance
            float currDist = Math.abs(finish - start);

            if (currDist <= rounding) return finish;

            if (currDist > smoothDistance)
                result = start + (speed * (delta / 16));
            else
                result = start + (((speed / smoothDistance) * currDist) * (delta / 16));

            if (((finish > 0) && (result > finish))
                || ((finish < 0) && (result < finish))) result = finish;

            return result;
        }

        return finish;
    }
    
    /** Smooth increment
     * @param start - Start value
     * @param finish - Finish value
     * @param delta - Time delta
     * @param speed - Speed
     * @param smoothDistance - Smooth distance
     * @return New value
     */
    static public float smoothIncrement(float start, float finish, int delta, float speed, float smoothDistance) {
    	return smoothIncrement(start, finish, delta, speed, smoothDistance, 0f);
    }
    
    /** Returns move vector
     * @param v1 - Vector1
     * @param v2 - Vector2
     * @return Move vector
     */
    static public Vector2f getMoveVector(Vector2f v1, Vector2f v2)
    {
        if (v1 != v2)
        {
            // Create move vector
            Vector2f moveVector = new Vector2f(0, 0);

            // Get X and Y distance
            float distX = Math.abs(v1.x - v2.x);
            float distY = Math.abs(v1.y - v2.y);

            // Calculate move vector
            if (distX > distY)
            {
                moveVector.x = 1;
                moveVector.y = distY / distX;
            }
            else if (distY > distX)
            {
                moveVector.x = distX / distY;
                moveVector.y = 1;
            }
            else if (distX == distY)
            {
                moveVector.x = 1;
                moveVector.y = 1;
            }

            // Set move vector
            if (v1.x > v2.x) moveVector.x = -moveVector.x;
            if (v1.y > v2.y) moveVector.y = -moveVector.y;

            return moveVector;
        }
        
        return new Vector2f(0, 0);
    }
	
}
